#include "SNMPDll.h"
#include <net-snmp\net-snmp-config.h>
#include <net-snmp\net-snmp-includes.h>

/*#define WIN32_LEAN_AND_MEAN
#include <windows.h>
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}*/

netsnmp_session *ss;

bool SNMPDLL_API dll_snmp_open(char* mibs_path, char* peername, bool snmpv3, char* security, char* password)
{	
	//init_snmp("snmpdemoapp"); 
	init_mib();
	add_mibdir(mibs_path);

	netsnmp_session session;
    snmp_sess_init(&session); 
    session.peername = strdup(peername);

	if(snmpv3)
	{
		session.version=SNMP_VERSION_3;        
    
		session.securityName    = strdup(security);
		session.securityNameLen = strlen(session.securityName);
		/* set the security level to authenticated, but not encrypted */
		session.securityLevel   = SNMP_SEC_LEVEL_AUTHNOPRIV;
		/* set the authentication method to MD5 */
		session.securityAuthProto    = usmHMACMD5AuthProtocol;
		session.securityAuthProtoLen = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid);
		session.securityAuthKeyLen   = USM_AUTH_KU_LEN;
		/* set the authentication key to a MD5 hashed version of our
		   passphrase "The Net-SNMP Demo Password" (which must be at least 8
		   characters long) */		
		if (generate_Ku(session.securityAuthProto,
						session.securityAuthProtoLen,
						(unsigned char *)password, 
						strlen(password),
						session.securityAuthKey,
						&session.securityAuthKeyLen)
						!= SNMPERR_SUCCESS) 
		{
			return false;
		}
	}    
	else
	{
		/* set the SNMP version number */
		session.version       = SNMP_VERSION_1;
		/* set the SNMPv1 community name used for authentication */
		session.community     = (unsigned char *)strdup(security);
		session.community_len = strlen((const char *)session.community);
	}

    SOCK_STARTUP;
    ss = snmp_open(&session);

    if (!ss) {
		return false;
    }

	return true;
}

bool SNMPDLL_API dll_snmp_close()
{	
    snmp_close(ss);
    SOCK_CLEANUP;
    return true;
}

bool SNMPDLL_API dll_snmp_command(char* oids, char type, unsigned char* value, unsigned int value_len)
{
	netsnmp_pdu* pdu = (struct snmp_pdu *)snmp_pdu_create(SNMP_MSG_SET);
	if(NULL == pdu)
	{
		return false;
	}

	oid name[MAX_OID_LEN];
	size_t name_len = MAX_OID_LEN;
	if(!read_objid(oids, name, (unsigned int *)&name_len)) 
	{
		return false;
	}

	snmp_pdu_add_variable(pdu, name, name_len, type, value, value_len);
	netsnmp_pdu *response = NULL;
	int status            = snmp_synch_response(ss, pdu, &response);	
	bool command_result   = false;

	if(status == STAT_SUCCESS) 
	{
		if (response->errstat == SNMP_ERR_NOERROR) 
		{
			command_result = true;
		}		
	} 
	
	if (response)
	{
		snmp_free_pdu(response);
	}

	return command_result;
}

int SNMPDLL_API dll_snmp_get_info(char* oids, unsigned char* type, char* value, unsigned int len)
{
	netsnmp_pdu* pdu = (struct snmp_pdu *)snmp_pdu_create(SNMP_MSG_GET);
	if(NULL == pdu)
	{
		return -1;
	}

	oid name[MAX_OID_LEN];
	size_t name_len = MAX_OID_LEN;
	if(!read_objid(oids, name, (unsigned int *)&name_len)) 
	{
		return -1;
	}

    snmp_add_null_var(pdu, name, name_len);  
    netsnmp_pdu *response = NULL;
	int status            = snmp_synch_response(ss, pdu, &response);
	int command_result    = -1;	
    
    if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) 
	{      
		netsnmp_variable_list* vars = response->variables;
		*type                        = vars->type;
		command_result              = len <= vars->val_len ? len : vars->val_len;
		memcpy(value, vars->val.string, command_result);		
	}

    if (response)
	{
		snmp_free_pdu(response);
	}
   
	return command_result;
}